#include <stdio.h>
#include <math.h>

#include "na_1.h"
#include "Auxiliary.h"

namespace na_13_ns
{

double PolyCalDirect( const double p_x, const int* p_coff, const unsigned int p_cnt )
{
    double ret = 0.0;

    for( unsigned int i = 0; i < p_cnt; ++i )
    {
        ret += (double)(p_coff[i])*pow(p_x, (double)(p_cnt-i-1));
    }

    return ret;
}

double PolyCalQJZ( const double p_x, const int* p_coff, const unsigned int p_cnt )
{
    double ret = 0.0;

    for( unsigned int i = 0; i < p_cnt-1; ++i )
    {
        ret += p_coff[i];
        ret *= p_x;
    }
    ret += p_coff[p_cnt-1];

    return ret;
}

double Taylor( const double p_x, const unsigned int p_n )
{
    //TODO
    //this part is somewhat difficult for programming differential function
    //so, temp to leave this to matlab
    //work on this in my general math lib

    return 0.0;
}

int na_13()
{
    printf("***************************************************\n");
    printf("Start the NA experiment 1.3, function approximation\n");

    const unsigned int n = 15;
    const unsigned int numeCnt = n+1-(n+2)/2;
    const unsigned int denoCnt = (n+2)/2;
    int numeCoff[numeCnt];//up
    int denoCoff[denoCnt];//down
    PolyCalFunctor polyCalFunc[2] = { NULL };

    polyCalFunc[0] = &PolyCalDirect;
    polyCalFunc[1] = &PolyCalQJZ;

    //init to cal coff
    int* biCoff = BinomalCoff(n);

    for( unsigned int i = 0; i < (n+1)/2; ++i )
    {
        numeCoff[i] = biCoff[2*i+1];
        denoCoff[i] = biCoff[2*i];
    }

    if ( n%2 == 0 )
    {
        denoCoff[numeCnt-1] = biCoff[n];
    }

    //output hint, and get input
    printf("approximation sqrt(2) with (sqrt(2)-1)^n, n=15:\n");
    printf("\t");
    for( unsigned int i = 0; i < numeCnt-2; ++i )
    {
        printf("%dx^%d+", numeCoff[i], n/2-i);
    }
    printf("%dx+", numeCoff[numeCnt-2]);
    printf("%d\n", numeCoff[numeCnt-1]);

    printf("g(x)=--------------------------------------------------\n");

    printf("\t");
    printf("x^%d+", n/2);
    for( unsigned int i = 1; i < denoCnt-2; ++i )
    {
        printf("%dx^%d+", denoCoff[i], n/2-i);
    }
    printf("%dx+", denoCoff[numeCnt-2]);
    printf("%d\n", denoCoff[denoCnt-1]);
    
    printf("set x to calculate g(x) value ( x [1, 2] ):");
    double initX = CheckedInputFloat( 1.0f, 2.0f );

    printf("choose way to calculate 1) Directly 2) QinJiuZhao:");
    static const char cValidInput[] = { '1', '2' };
    static const unsigned int cVInputCnt = 2;
    char funcNo = CheckedInputChar( cValidInput, cVInputCnt ) - '1';

    double result = polyCalFunc[funcNo](initX, numeCoff, numeCnt) / polyCalFunc[funcNo](initX, denoCoff, denoCnt);

    printf("g(x) = %1.12f, while sqrt(x) = %1.12f \n", result, sqrt(initX));

    printf("End of function approximation\n");
    printf("***************************************************\n");
    return 0;
}

}
